package com.apobates.forum.thrones.controller;

import com.apobates.forum.core.entity.BoardTopicCategoryIndex;
import com.apobates.forum.core.entity.ForumReportTypeEnum;
import com.apobates.forum.core.entity.proxy.BoardGroupReplica;
import com.apobates.forum.core.entity.proxy.TopicReplica;
import com.apobates.forum.core.service.BoardGroupService;
import com.apobates.forum.core.service.BoardTopicCategoryIndexService;
import com.apobates.forum.core.service.TopicService;
import com.apobates.forum.event.elderly.ActionEventCulpritor;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.member.entity.MemberSocialInfo;
import com.apobates.forum.member.service.MemberService;
import com.apobates.forum.member.service.MemberSocialInfoService;
import com.apobates.forum.member.storage.core.MemberSessionBean;
import com.apobates.forum.thrones.controller.form.MemberPassworResetForm;
import com.apobates.forum.thrones.controller.form.MemberPasswordLostForm;
import com.apobates.forum.thrones.controller.helper.FeedbackPlugTopic;
import com.apobates.forum.thrones.controller.helper.OnlineDescriptor;
import com.apobates.forum.thrones.exception.ResourceNotFoundException;
import com.apobates.forum.utils.Commons;
import com.apobates.forum.utils.TipMessage;
import com.apobates.forum.utils.lang.EnumArchitecture;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 主控制器
 * 
 * @author xiaofanku
 * @since 20200511
 */
@Controller
public class MainController {
    @Autowired
    private TopicService topicService;
    @Autowired
    private BoardGroupService boardGroupService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private MemberSocialInfoService memberSocialInfoService;
    @Autowired
    private BoardTopicCategoryIndexService boardTopicCategoryIndexService;
    @Value("${site.domain}")
    private String siteDomain;
    @Value("${site.dec.salt}")
    private String globalDecSalt;
    
    // 随便看看(站内动态)
    @GetMapping(path = "/home")
    @OnlineDescriptor(action=ForumActionEnum.COMMON_CASUAL)
    public String home(
            HttpServletRequest request,
            @RequestParam(value="pageSize",required = false, defaultValue = "10") int pageSize,
            Model model) {
        //结果集
        Stream<TopicReplica> rs = topicService.getRecentRelateContent(pageSize).stream();
        model.addAttribute("rs", rs.sorted(Comparator.comparing(TopicReplica::getRankingDateTime).reversed()).collect(Collectors.toList()));
        return "default/index";
    }
    
    // 所有版块
    @GetMapping(path = "/board/home")
    public String listBoard(MemberSessionBean mbean, HttpServletRequest request, Model model) {
        List<BoardGroupReplica> rs = boardGroupService.getAllUsedAndBoard(true);
        model.addAttribute("rs", rs);
        return "default/board/index";
    }
    
    // 找回密码:第一步
    @GetMapping(path = "/lostPswd")
    public String resetPswdOneStepForm(
            @RequestParam(value = "token", required = false, defaultValue = "0") String token,
            HttpServletRequest request,
            Model model) {
        MemberPasswordLostForm form = new MemberPasswordLostForm();
        form.setToken(token);
        model.addAttribute("form", form);
        return "index";
    }
    @PostMapping(path = "/lostPswd")
    public String resetPswdOneStepAction(
            @ModelAttribute("form") MemberPasswordLostForm form,
            HttpServletRequest request,
            Model model) {
        MemberSocialInfo rmsi = memberSocialInfoService.getByMember(form.getNames(), form.getEmail(), globalDecSalt).orElseThrow(()->new ResourceNotFoundException("请确认帐号是否已与邮箱关联"));
        long mid = rmsi.getMemberId();
        String v = Commons.base64Encode(encodeJsonString(mid, form.getToken(), 3, System.currentTimeMillis()), ()->null);
        if(null != v){
            return String.format("redirect:/rsetPswd?token=%s&id=%d&v=%s", form.getToken(), mid, v);
        }
        model.addAttribute("form", form);
        model.addAttribute("errors", "计算下一步编码失败");
        return "index";
    }
    
    // 找回密码:第二步
    @GetMapping(path = "/rsetPswd")
    public String resetPswdTwoStepForm(
            @RequestParam(value = "token", required = false, defaultValue = "0") String token,
            @RequestParam("id") long memberId,
            @RequestParam("v") String hashValue,
            HttpServletRequest request,
            Model model) {
        MemberPassworResetForm form = new MemberPassworResetForm();
        form.setToken(token);
        form.setRecord(memberId);
        form.setDisi(hashValue);
        model.addAttribute("form", form);
        return "rsetPswd";
    }
    @PostMapping(path = "/rsetPswd")
    public String resetPswdTwoStepAction(
            @ModelAttribute("form") MemberPassworResetForm form,
            HttpServletRequest request,
            Model model) {
        if (!Commons.isNotBlank(form.getDisi())) {
            model.addAttribute("form", form);
            model.addAttribute("errors", "操作需要的参数丢失");
            return "rsetPswd";
        }
        Map<String, String> disiMap = decodeJsonString(Commons.base64Decode(form.getDisi(), ()->null), 4);
        if (disiMap.isEmpty()) {
            model.addAttribute("form", form);
            model.addAttribute("errors", "参数信息不完整");
            return "rsetPswd";
        }
        //
        long finishTimeMills = System.currentTimeMillis();
        long startTimeMills = Commons.stringToLong(disiMap.getOrDefault("timestamp", null), finishTimeMills);
        //
        if (finishTimeMills == startTimeMills || finishTimeMills - startTimeMills > 360000) {
            model.addAttribute("form", form);
            model.addAttribute("errors", "操作已经超时,请在3分钟内完成");
            return "rsetPswd";
        }
        boolean data = memberService.resetPswd(form.getLongRecord(), form.getConfirmpswd(), MemberController.getInstance(request, form.getToken())).orElse(false);
        if (data) {
            //--------------------------------------------------
            // 密码变化通知
            //--------------------------------------------------
            return "redirect:/rsetPswd/success.xhtml";
        }
        model.addAttribute("errors", "重置密码操作失败,请稍候重新尝试");
        return "rsetPswd";
    }
    
    // 找回密码:第三步
    @GetMapping(path = "/rsetPswd/success.xhtml")
    public String rsetPswdSuccess(HttpServletRequest request, Model model) throws IllegalAccessException {
        //来源页判断 http Referer:site.domain{http://center.test.com}/rsetPswd
        String reqRef = request.getHeader("referer");
        if (null == reqRef || !reqRef.equals(siteDomain + "/rsetPswd")) {
            throw new IllegalAccessException("非法的请求路径");
        }
        return "rsetPswd_success";
    }
    
    // 举报回复的类别
    @GetMapping(path = "/report/type", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public Map<Integer, String> getReportType(HttpServletRequest request, Model model) {
        return EnumArchitecture.getInstance(ForumReportTypeEnum.class);
    }
    
    //意见反馈
    @PostMapping(path = "/feedback", produces = "application/json;charset=UTF-8")
    @ResponseBody
    @OnlineDescriptor(action=ForumActionEnum.COMMON_FEEDBACK)
    public TipMessage feedback(
            @RequestParam("title") String title,
            @RequestParam("content") String content,
            @RequestParam(value = "token", required = false, defaultValue = "0") String token,
            MemberSessionBean mbean,
            HttpServletRequest request,
            Model model) {
        ActionEventCulpritor aec = BoardController.getInstance(mbean.getMid(), mbean.getNickname(), request, token);
        Optional<BoardTopicCategoryIndex> btc = boardTopicCategoryIndexService.getFeedbackRelativeRecord();
        if(!btc.isPresent()){
            return TipMessage.ofError("未知的存储目标");
        }
        return TipMessage.Builder.of(()->topicService.plug(new FeedbackPlugTopic(aec, title, content, btc.get())).isPresent()).success("感谢您反馈的意见或建议").error("操作失败");
    }
    private String encodeJsonString(long mid, String token, int limit, long timestamp) {
        Map<String, String> data = Map.ofEntries(Map.entry("mid", mid + ""), Map.entry("token", token), Map.entry("limit", limit + ""), Map.entry("timestamp", timestamp + ""));
        return Commons.toJson(data);
    }
    
    private Map<String, String> decodeJsonString(String jsonString, int keySize) {
        if(null == jsonString){
            return Collections.emptyMap();
        }
        Map<String, String> data = Commons.fromString(jsonString);
        if (null == data || data.isEmpty() || data.size() != keySize) {
            return Collections.emptyMap();
        }
        return data;
    }
}